package main

import (
	"Server/goModule/hyper"
	"Server/utils"
	"bufio"
	"fmt"
	"github.com/gogf/gf/v2/container/garray"
	"github.com/gogf/gf/v2/container/gmap"
	lua "github.com/yuin/gopher-lua"
	"github.com/yuin/gopher-lua/parse"
	"os"
)

var libCompiledList garray.Array

var serviceCompliedMap gmap.StrAnyMap

type LuaHelper struct {
	L *lua.LState
}

func NewLuaHelper() *LuaHelper {
	return &LuaHelper{
		L: lua.NewState(),
	}
}

func (this *LuaHelper) Init() {
	this.InitGoModule()
	this.InitLibLua()
	this.InitServiceLua("TestService")
}

func (this *LuaHelper) InitGoModule() {
	this.L.PreloadModule("hyper", func(L *lua.LState) int {
		mod := L.SetFuncs(L.NewTable(), hyper.HyperExports)
		L.SetField(mod, "name", lua.LString("value"))
		L.Push(mod)
		return 1
	})
}

func (this *LuaHelper) InitLibLua() {
	libCompiledList.Iterator(func(k int, v interface{}) bool {
		err := DoCompiledFile(this.L, v.(*lua.FunctionProto))
		if err != nil {
			fmt.Printf("load lua err %s", err.Error())
		}
		return true
	})
}

func (this *LuaHelper) InitServiceLua(serviceName string) {
	p := serviceCompliedMap.Get(serviceName)
	if p == nil {
		fmt.Printf("service %s not found", serviceName)
		return
	}
	err := DoCompiledFile(this.L, p.(*lua.FunctionProto))
	if err != nil {
		fmt.Printf("load lua err %s", err.Error())
	}
}

func (this *LuaHelper) Close() {
	if this.L != nil {
		this.L.Close()
	}
}

// CompileLua reads the passed lua file from disk and compiles it.
func CompileLua(filePath string) (*lua.FunctionProto, error) {
	file, err := os.Open(filePath)
	defer file.Close()
	if err != nil {
		return nil, err
	}
	reader := bufio.NewReader(file)
	chunk, err := parse.Parse(reader, filePath)
	if err != nil {
		return nil, err
	}
	proto, err := lua.Compile(chunk, filePath)
	if err != nil {
		return nil, err
	}
	return proto, nil
}

// DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent
// to calling DoFile on the LState with the original source file.
func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error {
	lfunc := L.NewFunctionFromProto(proto)
	L.Push(lfunc)
	return L.PCall(0, lua.MultRet, nil)
}

func CompliedLibLua(libPath *garray.StrArray) {
	libPath.Iterator(func(k int, v string) bool {
		// 扫描路径下所有lua文件
		files, e := utils.FindLuaFiles(v)
		if e != nil {
			fmt.Printf("load lua err %s", e.Error())
			return true
		}
		for _, filePath := range files {
			p, err := CompileLua(filePath)
			if err != nil {
				fmt.Printf("load lua err %s", err.Error())
				return true
			}
			libCompiledList.Append(p)
		}
		return true
	})
}

func CompliedServiceLua(serviceName string, serviceFilePath string) {
	p, err := CompileLua(serviceFilePath)
	if err != nil {
		fmt.Printf("CompliedServiceLua err %s", err.Error())
	}
	serviceCompliedMap.Set(serviceName, p)
}
